package ru.susu.algebra.chartable.writer;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.math.BigInteger;
import java.util.List;

import ru.susu.algebra.chartable.constructor.AlternatingCharTableUtil;
import ru.susu.algebra.chartable.constructor.AlternatingGroupCharTableConstructor;
import ru.susu.algebra.chartable.constructor.IPermCharTableConstructor;
import ru.susu.algebra.matrix.Matrix;
import ru.susu.algebra.partition.Partition;
import ru.susu.algebra.partition.PartitionsCacheConstructor;
import ru.susu.algebra.partition.comparators.AlternatingByCharDegreeComparator;
import ru.susu.algebra.partition.filter.AlternatingPartitionsFilter;
import ru.susu.algebra.partition.filter.OnlyFirstAssocPartitionFilter;
import ru.susu.algebra.properties.IPropertySource;
import ru.susu.algebra.properties.MapPropertySource;
import ru.susu.algebra.transformers.DummyObjectTransformer;
import ru.susu.algebra.transformers.IObjectTransformer;
import ru.susu.algebra.ui.field.ILegendField;
import ru.susu.algebra.util.CollectionUtils;
import ru.susu.algebra.util.StringUtilities;

/**
 * @author akargapolov
 * @since: 09.03.2009
 */
public class StWorkspaceAllAlternatingGroupCharTableWriter
{
	public static final String VALUE_TRANSFORMER = "ValueTransformer";
	public static final IObjectTransformer<BigInteger> DEFAULT_TRANSFORMER = new DummyObjectTransformer<BigInteger>();

	private int _width;

	private IPropertySource _ps;

	public StWorkspaceAllAlternatingGroupCharTableWriter()
	{
		this(new MapPropertySource());
	}

	public StWorkspaceAllAlternatingGroupCharTableWriter(IPropertySource ps)
	{
		_ps = ps;
	}

	public void write(Integer number) throws Exception
	{
		PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("ExecuteResults/AltCharTables/" + number
				+ ".txt")));

		List<Partition> partitions1 = new PartitionsCacheConstructor().getAscendingPartitions(number,
				new OnlyFirstAssocPartitionFilter());
		List<Partition> partitions2 = new PartitionsCacheConstructor().getAscendingPartitions(number,
				new AlternatingPartitionsFilter());

		AlternatingGroupCharTableConstructor constructor = AlternatingGroupCharTableConstructor.getInstance();

		partitions1 = CollectionUtils.sort(partitions1, true, new AlternatingByCharDegreeComparator());

		calculateWidth(constructor, partitions1, partitions2);

		writeMatrix(constructor, partitions1, partitions2, out);

		writeLegendFields(constructor, partitions1, partitions2, out);
		out.close();
	}

	private void calculateWidth(IPermCharTableConstructor<Matrix> constructor, List<Partition> partitions1,
			List<Partition> partitions2) throws Exception
	{
		_width = 1;
		for (Partition p1 : partitions1)
		{
			for (Partition p2 : partitions2)
			{
				Matrix value = constructor.getValue(p1, p2);
				for (int i = 0; i < value.getRows(); i++)
					for (int j = 0; j < value.getCols(); j++)
					{
						_width = Math.max(_width, getTransformedValue(value.getValue(i, j)).toString().length() + 1);
					}
			}
		}
	}

	private void writeMatrix(IPermCharTableConstructor<Matrix> constructor, List<Partition> partitions1,
			List<Partition> partitions2, Writer out) throws Exception
			{
		int number = partitions1.get(0).getPresentedNumber();

		int index = 0;
		// head
		for (Partition p2 : partitions2)
		{
			int curWidth = index == 0 ? _width * 2 + 1 : _width;
			out.write(StringUtilities.toString(p2.getOrderNumber(), curWidth));
			if (AlternatingCharTableUtil.isSpecialColumn(p2) && number > 1)
				out.write(StringUtilities.toString(p2.getOrderNumber(), _width));
			index++;
		}
		out.write("\n");
		index = 0;
		for (Partition p1 : partitions1)
		{
			writeLine(constructor, p1, partitions2, 0, out);
			if (AlternatingCharTableUtil.isSpecialRow(p1) && number > 1)
			{
				writeLine(constructor, p1, partitions2, 1, out);
			}

		}
			}

	private void writeLine(IPermCharTableConstructor<Matrix> constructor, Partition p1, List<Partition> partitions,
			int i, Writer out) throws Exception
	{
		out.write(StringUtilities.toString(p1.getOrderNumber(), _width) + ":");
		for (Partition p2 : partitions)
		{
			Matrix value = constructor.getValue(p1, p2);
			for (int j = 0; j < value.getCols(); j++)
			{
				Object obj = getTransformedValue(value.getValue(i, j));
				out.write(StringUtilities.toString(obj.toString(), _width));
			}
		}
		out.write("\n");
	}

	private void writeLegendFields(IPermCharTableConstructor<Matrix> constructor, List<Partition> partitions1,
			List<Partition> partitions2, Writer out) throws Exception
			{
		Integer number = Integer.valueOf(0);
		for (Partition p1 : partitions1)
		{
			for (Partition p2 : partitions2)
			{
				Matrix value = constructor.getValue(p1, p2);
				if (value.getValue(0, 0) instanceof ILegendField)
				{
					ILegendField field = (ILegendField) value.getValue(0, 0);
					out.write(field.getIdentifier() + " = " + field.getValue().toString() + "\n");
				}
			}
		}
			}

	private Object getTransformedValue(Object source)
	{
		if (source instanceof BigInteger)
		{
			BigInteger bigInt = (BigInteger)source;
			IObjectTransformer<BigInteger> transformer = (IObjectTransformer<BigInteger>)_ps.getValue(VALUE_TRANSFORMER, DEFAULT_TRANSFORMER);
			return transformer.transformObject(bigInt);
		}
		return source;
	}
}
